using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using BroRPG.GameComponents;

namespace BroRPG
{

    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;

        Sprite player;

        float ambientFactor = 1.2f;

        Color ambientColor = Color.White;

        List<Tuile> backGround = new List<Tuile>();
        List<Light> lights = new List<Light>();

        List<Chunck> chuncks = new List<Chunck>();

        Vector2 lastPlayerPos = new Vector2(1,1);
        int lastXCase = 0;
        int lastYCase =0;

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            graphics.PreferredBackBufferHeight = 600;
            graphics.PreferredBackBufferWidth = 800;
            Content.RootDirectory = "Content";
           // TargetElapsedTime = TimeSpan.FromTicks(333333);
        }

        protected override void Initialize()
        {
            base.Initialize();
        }

        protected override void LoadContent()
        {
            spriteBatch = new SpriteBatch(GraphicsDevice);

            



            //init constants
            Constants.Content = Content;
            Constants.Spritebatch = spriteBatch;

            Constants.SpriteSheets.Add("player", Content.Load<SpriteSheetRuntime.SpriteSheet>("Ressources/Textures/Player"));
            Constants.SpriteSheets.Add("world", Content.Load<SpriteSheetRuntime.SpriteSheet>("Ressources/Textures/World"));
            Constants.Fonts.Add("FPS", Content.Load<SpriteFont>("Ressources/Fonts/FPS"));
            Constants.Game = this;

            FrameRateCounter counter = new FrameRateCounter();
            this.Components.Add(counter);

            Sprite.bounds = Constants.Content.Load<Texture2D>("Ressources/Textures/bound");

            player = new Player("player", "PlayerPaper", new Vector2(0, 0));
            player.Light = 0.5f;


            //create base chunk
            this.chuncks.Add(new Chunck(0, 0, 1));
            this.chuncks.Add(new Chunck(0, -1));
            this.chuncks.Add(new Chunck(0, 1));

            this.chuncks.Add(new Chunck(-1, 0));
            this.chuncks.Add(new Chunck(-1, -1));
            this.chuncks.Add(new Chunck(-1, 1));

            this.chuncks.Add(new Chunck(1, 0));
            this.chuncks.Add(new Chunck(1, -1));
            this.chuncks.Add(new Chunck(1, 1));

            int playerChunckX = (int)(player.Position.X / Chunck.CHUNCK_WIDTH);
            int playerChunckY = (int)(player.Position.Y / Chunck.CHUNCK_HEIGHT);

            int playerCaseX = (int)(player.Position.X / 40);
            int playerCaseY = (int)(player.Position.Y / 40);
            for (int x = -Chunck.CHUNCK_SIZE_X / 2 - 2; x < Chunck.CHUNCK_SIZE_X / 2 + 2; x++)
            {
                for (int y = -Chunck.CHUNCK_SIZE_Y / 2 - 2; y < Chunck.CHUNCK_SIZE_Y / 2 + 2; y++)
                {
                    int caseX = (playerCaseX + x);
                    int caseY = (playerCaseY + y);

                    int ChunckPosX = caseX / Chunck.CHUNCK_SIZE_X;
                    if (caseX < 0)
                        ChunckPosX--;

                    int ChunckPosY = caseY / Chunck.CHUNCK_SIZE_Y;
                    if (caseY < 0)
                        ChunckPosY--;


                    int ChunckCaseX = 0;
                    if (caseX >= 0)
                        ChunckCaseX = caseX % Chunck.CHUNCK_SIZE_X;
                    else
                    {
                        int tmp = Math.Abs(caseX) % Chunck.CHUNCK_SIZE_X;
                        ChunckCaseX = Chunck.CHUNCK_SIZE_X - tmp;
                    }

                    int ChunckCaseY = 0;
                    if (caseY >= 0)
                        ChunckCaseY = caseY % Chunck.CHUNCK_SIZE_Y;
                    else
                    {
                        int tmp = Math.Abs(caseY) % Chunck.CHUNCK_SIZE_Y;
                        ChunckCaseY = Chunck.CHUNCK_SIZE_Y - tmp;
                    }

                    Chunck validChunck = chuncks.FirstOrDefault(c => c.X == ChunckPosX && c.Y == ChunckPosY);
                    if (validChunck != null)
                    {
                        foreach (var item in validChunck.Render(ChunckCaseX, ChunckCaseY))
                        {
                            item.Position = new Vector2(item.Position.X - player.Position.X + 400, item.Position.Y - player.Position.Y + 300);
                            backGround.Add(item);
                        }

                    }
                }
            }


            
            /*
            for (int y = 0; y < 15; y++)
            {
                for (int x = 0; x < 20; x++)
                {
                    if (y == 0 || y == 3)
                    {
                        Tuile tile = new Tuile("world", "carre", 1);
                        tile.MaterialColor = Color.White;
                        tile.Position = new Vector2(x * 40 + 20, y * 40 + 20);
                        backGround.Add(tile);
                    }
                    else if (y == 1 || y == 2)
                    {
                        

                        Tuile tile = new Tuile("world", "tile", 0);
                        tile.MaterialColor = Color.White;
                        tile.Position = new Vector2(x * 40 + 20, y * 40 + 20);
                        backGround.Add(tile);

                        Tuile toit = new Tuile("world", "carre", 2);
                        toit.MaterialColor = Color.Green;
                        toit.Position = new Vector2(x * 40 + 20, y * 40 + 20);
                        backGround.Add(toit);
                    }
                    else
                    {
                        Tuile tile = new Tuile("world", "carre", 0);
                        tile.MaterialColor = Color.DarkGreen; //Color.White;
                        tile.Position = new Vector2(x * 40 + 20, y * 40 + 20);
                        backGround.Add(tile);
                    }
                }
            }
          



            Light light1 = new Light(new Vector2(0, 0)) { Color = Color.Yellow, Distance = 200 };
            Light light2 = new Light(new Vector2(800, 600)) { Color = Color.Yellow, Distance = 300 };
            Light light3 = new Light(new Vector2(800, 0)) { Power = 2 };


            lights.Add(light1);
            lights.Add(light2);
            lights.Add(light3);
             *   */

            Light light1 = new Light(new Vector2(0, 0)) { Color = Color.Yellow, Distance = 300 };
            lights.Add(light1);
        }

        protected override void UnloadContent()
        {
            

            
        }

        KeyboardState currentKeyboard;
        MouseState currentMouse;
        protected override void Update(GameTime gameTime)
        {

            currentKeyboard = Keyboard.GetState();
            currentMouse = Mouse.GetState();


            lights[0].Position = new Vector2(400,300);

            if (currentKeyboard.IsKeyDown(Keys.Space))
                if (ambientFactor <= 0.02)
                    ambientFactor = 1.2f;
                else
                    ambientFactor -= 0.02f;

        
            if (currentKeyboard.IsKeyDown(Keys.NumPad0))
            {
                foreach (var item in this.backGround.Where(p=>p.Layer == 2).ToList())
                {

                    if (item.Alpha <= 0.01)
                        item.Alpha = 1;
                    else
                        item.Alpha -= 0.01f;
                }
            }



            if (currentKeyboard.IsKeyDown(Keys.Left))
                player.Position = new Vector2(player.Position.X - 5, player.Position.Y);
            if (currentKeyboard.IsKeyDown(Keys.Right))
                player.Position = new Vector2(player.Position.X + 5, player.Position.Y);
            if (currentKeyboard.IsKeyDown(Keys.Up))
                player.Position = new Vector2(player.Position.X, player.Position.Y -5);
            if (currentKeyboard.IsKeyDown(Keys.Down))
                player.Position = new Vector2(player.Position.X, player.Position.Y + 5);

           

            player.Light = 1f;
            player.Update(gameTime);

            

            if (lastPlayerPos != player.Position)
            {
               // backGround.Clear();

                Vector2 ecartLastPos = player.Position - lastPlayerPos;
                foreach (var item in backGround)
                {
                    item.Position = new Vector2(item.Position.X - ecartLastPos.X, item.Position.Y - ecartLastPos.Y);
                }

                lastPlayerPos = new Vector2(player.Position.X, player.Position.Y);

                int playerChunckX = (int)(player.Position.X / Chunck.CHUNCK_WIDTH);
                int playerChunckY = (int)(player.Position.Y / Chunck.CHUNCK_HEIGHT);

                int playerCaseX = (int)(player.Position.X / 40);
                int playerCaseY = (int)(player.Position.Y / 40);
                
                if (playerCaseX != lastXCase )
                {
                    int ecart = playerCaseX - lastXCase;
                    int x = playerCaseX + (Chunck.CHUNCK_SIZE_X / 2) * ecart ;
                    for (int y = -Chunck.CHUNCK_SIZE_Y/2; y < Chunck.CHUNCK_SIZE_Y/2; y++)
                    {
                        int caseX =  x;
                        int caseY = playerCaseY + y;

                        int ChunckPosX = caseX / Chunck.CHUNCK_SIZE_X;
                        if (caseX < 0)
                            ChunckPosX--;

                        int ChunckPosY = caseY / Chunck.CHUNCK_SIZE_Y;
                        if (caseY < 0)
                            ChunckPosY--;


                        int ChunckCaseX = 0;
                        if (caseX >= 0)
                            ChunckCaseX = caseX % Chunck.CHUNCK_SIZE_X;
                        else
                        {
                            int tmp = Math.Abs(caseX) % Chunck.CHUNCK_SIZE_X;
                            ChunckCaseX = Chunck.CHUNCK_SIZE_X - tmp;
                        }

                        int ChunckCaseY = 0;
                        if (caseY >= 0)
                            ChunckCaseY = caseY % Chunck.CHUNCK_SIZE_Y;
                        else
                        {
                            int tmp = Math.Abs(caseY) % Chunck.CHUNCK_SIZE_Y;
                            ChunckCaseY = Chunck.CHUNCK_SIZE_Y - tmp;
                        }

                        Chunck validChunck = chuncks.FirstOrDefault(c => c.X == ChunckPosX && c.Y == ChunckPosY);
                        if (validChunck != null)
                        {
                            foreach (var item in validChunck.Render(ChunckCaseX, ChunckCaseY))
                            {
                                item.Position = new Vector2(item.Position.X - player.Position.X + 400, item.Position.Y - player.Position.Y + 300);
                                backGround.Add(item);
                            }

                        }
                    }
                }

                if (playerCaseY != lastYCase)
                {
                    int ecart = playerCaseY - lastYCase;
                    int y = playerCaseY + (Chunck.CHUNCK_SIZE_Y / 2) * ecart - ecart;
                    for (int x = -Chunck.CHUNCK_SIZE_X / 2; x < Chunck.CHUNCK_SIZE_X / 2; x++)
                    {
                        int caseY = y;
                        int caseX = playerCaseX + x;

                        int ChunckPosX = caseX / Chunck.CHUNCK_SIZE_X;
                        if (caseX < 0)
                            ChunckPosX--;

                        int ChunckPosY = caseY / Chunck.CHUNCK_SIZE_Y;
                        if (caseY < 0)
                            ChunckPosY--;


                        int ChunckCaseX = 0;
                        if (caseX >= 0)
                            ChunckCaseX = caseX % Chunck.CHUNCK_SIZE_X;
                        else
                        {
                            int tmp = Math.Abs(caseX) % Chunck.CHUNCK_SIZE_X;
                            ChunckCaseX = Chunck.CHUNCK_SIZE_X - tmp;
                        }

                        int ChunckCaseY = 0;
                        if (caseY >= 0)
                            ChunckCaseY = caseY % Chunck.CHUNCK_SIZE_Y;
                        else
                        {
                            int tmp = Math.Abs(caseY) % Chunck.CHUNCK_SIZE_Y;
                            ChunckCaseY = Chunck.CHUNCK_SIZE_Y - tmp;
                        }

                        Chunck validChunck = chuncks.FirstOrDefault(c => c.X == ChunckPosX && c.Y == ChunckPosY);
                        if (validChunck != null)
                        {
                            foreach (var item in validChunck.Render(ChunckCaseX, ChunckCaseY))
                            {
                                item.Position = new Vector2(item.Position.X - player.Position.X + 400, item.Position.Y - player.Position.Y + 300);
                                backGround.Add(item);
                            }

                        }
                    }
                }

                lastXCase = playerCaseX;
                lastYCase = playerCaseY;
                

              /*  for (int x = -Chunck.CHUNCK_SIZE_X/2 - 2; x < Chunck.CHUNCK_SIZE_X/2+ 2; x++)
                {
                    for (int y = -Chunck.CHUNCK_SIZE_Y/2 -2 ; y < Chunck.CHUNCK_SIZE_Y/2+2; y++)
                    {
                        int caseX = (playerCaseX + x);
                        int caseY = (playerCaseY + y);

                        int ChunckPosX = caseX / Chunck.CHUNCK_SIZE_X;
                        if (caseX < 0)
                            ChunckPosX--;

                        int ChunckPosY = caseY / Chunck.CHUNCK_SIZE_Y;
                        if (caseY < 0)
                            ChunckPosY--;


                        int ChunckCaseX = 0;
                        if (caseX >= 0)
                            ChunckCaseX = caseX % Chunck.CHUNCK_SIZE_X;
                        else
                        {
                            int tmp = Math.Abs(caseX) % Chunck.CHUNCK_SIZE_X;
                            ChunckCaseX = Chunck.CHUNCK_SIZE_X - tmp;
                        }

                        int ChunckCaseY = 0;
                        if (caseY >= 0)
                            ChunckCaseY = caseY % Chunck.CHUNCK_SIZE_Y;
                        else
                        {
                            int tmp = Math.Abs(caseY) % Chunck.CHUNCK_SIZE_Y;
                            ChunckCaseY = Chunck.CHUNCK_SIZE_Y - tmp;
                        }

                      Chunck validChunck = chuncks.FirstOrDefault(c => c.X == ChunckPosX && c.Y == ChunckPosY);
                      if (validChunck != null)
                      {
                          foreach (var item in validChunck.Render(ChunckCaseX, ChunckCaseY))
                          {
                              item.Position = new Vector2(item.Position.X - player.Position.X + 400, item.Position.Y - player.Position.Y + 300);
                              backGround.Add(item);
                          }
                          
                      }
                    }
                }*/
                 

                

              


                

            }

            foreach (var item in this.backGround)
            {
                item.Update(gameTime);
            }

            foreach (Light lumiere in lights)
            {
                List<Tuile> lightedSprites = displayedSprites().Where(s => Math.Sqrt(
                                                                        Math.Pow(s.Position.X - lumiere.Position.X, 2) +
                                                                        Math.Pow(s.Position.Y - lumiere.Position.Y, 2)
                                                                    ) <= lumiere.Distance)
                                                                    .ToList();

                foreach (Sprite lightedSprite in lightedSprites)
                {
                    double distance = Math.Sqrt(Math.Pow(lightedSprite.Position.X - lumiere.Position.X, 2) +
                                            Math.Pow(lightedSprite.Position.Y - lumiere.Position.Y, 2));

                    float lightValue = (1 - (float)(distance / lumiere.Distance)) * (1 - ambientFactor) * lumiere.Power;

                    if (lightedSprite.Light < lightValue)
                    {
                        lightedSprite.Light = lightValue;
                        lightedSprite.LightColor = lumiere.Color;
                    }
                    else
                    {
                        lightedSprite.LightColor = new Color(lightedSprite.LightColor.R + lumiere.Color.R, lightedSprite.LightColor.G + lumiere.Color.G, lightedSprite.LightColor.B + lumiere.Color.B);
                    }
                }
            }

            backGround = displayedSprites();

            base.Update(gameTime);
        }

        private List<Tuile> displayedSprites()
        {

            List<Tuile> retour = backGround.Where(s=>Math.Sqrt(     Math.Pow(s.Position.X - 400, 2) +
                                                                        Math.Pow(s.Position.Y - 300, 2)
                                                                    ) <= 540).ToList();

            return retour;
        }


        protected override void Draw(GameTime gameTime)
        {

            GraphicsDevice.Clear(Color.CornflowerBlue);


            foreach (var item in displayedSprites())
            {
                item.Draw(gameTime, ambientFactor, ambientColor);
               // item.DrawBounds(gameTime, 0, Color.Black);
            }

            player.Draw(gameTime, (ambientFactor > 0.5f ? ambientFactor : 0.5f), ambientColor);
            //player.DrawBounds(gameTime);
            base.Draw(gameTime);
        }
    }
}
